package com.paradogs.demo.logic.misc;

import com.paradogs.demo.logic.manager.base.BaseManager;
import com.paradogs.framework.core.annoations.request.PRMsgMapping;
import com.paradogs.framework.core.msg.PRMsgContextHolder;
import com.paradogs.framework.core.msg.R;
import com.paradogs.framework.core.utils.MsgUtils;
import com.paradogs.framework.core.utils.ReflectUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

/**
 * @author: yumi
 * @date: 2023/11/30  17:55
 * @Description: 检查和同步玩家数据变化的切面
 */
@Slf4j
@Aspect
@Order(Integer.MAX_VALUE)
@Component
public class SyncAspect {

    @Autowired
    private PlayerOnlineHolder onlineHolder;

    /**
     * 对 @PRMsgMapping 注解方法切面，用于检查和同步玩家数据变化
     * - @within(com.paradogs.framework.core.annoations.request.PRController) &&
     * @param joinPoint
     * @param msgMapping
     * @return
     * @throws Throwable
     */
    @Around("@annotation(msgMapping)")
    public Object aroundPRMsgMappingMethods(ProceedingJoinPoint joinPoint, PRMsgMapping msgMapping) throws Throwable {
        Object result = joinPoint.proceed(); // 执行目标方法
        Long uId = PRMsgContextHolder.getPlayerId();
        PlayerTemplate template = onlineHolder.getPlayer(uId);
        /**
         * 玩家数据发生变化时，同步数据（先发送同步消息再发送回复消息）
         * 待优化：
         * 1. 目前变化时同步整个类，可以改成同步类中单个字段
         * 2. syncData 消息和 reply 消息合并发送：合并成同一个类或 write() 不 flush ?
         */
        if (template != null) {
            R syncData = R.success(result);
            boolean needSync = false;
            for (BaseManager manager : template.getManagers()) {
                if (manager.isDirty()) {
                    ReflectUtils.callSetter(syncData, manager.getData().getClass().getSimpleName(), manager.getData());
                    needSync = true;
                }
            }
            // 如果玩家数据变化，则同步玩家数据
            if (needSync) {
                syncData.setPlayerId(uId);
                MsgUtils.send("gate|syncData", syncData, PRMsgContextHolder.getChannel());
                log.debug("数据变化，同步玩家数据: {}", syncData);
            }
            // 更新数据状态
            template.getManagers().forEach(manager -> manager.setDirty(false));
        }

        return result;
    }

}
